﻿using DataAnalyticsTools.Models;
using MathNet.Numerics.Statistics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataAnalyticsTools.Core
{
    public static class CorrelationAnalyzer
    {
        /// <summary>
        /// 计算皮尔逊相关系数矩阵
        /// 衡量特征之间的线性相关程度，值域[-1, 1]
        /// </summary>
        /// <param name="data">特征矩阵，形状为[样本数, 特征数]</param>
        /// <returns>
        /// 相关系数矩阵，形状为[特征数, 特征数]
        /// 对角线为1，对称矩阵，值越接近±1表示相关性越强
        /// </returns>
        /// <example>
        /// 输入: [[1, 2, 3], [2, 4, 6], [3, 6, 9]]
        /// 输出: 
        ///   [1, 1, 1]
        ///   [1, 1, 1] 
        ///   [1, 1, 1]  // 所有特征完全正相关
        /// </example>
        public static float[,] PearsonCorrelationMatrix(float[][] data)
        {
            if (data == null || data.Length == 0)
                return new float[0, 0];

            if (data.Length < 2)
                throw new ArgumentException("计算相关系数至少需要2个样本");

            int featureCount = data[0].Length;
            var corrMatrix = new float[featureCount, featureCount];

            for (int i = 0; i < featureCount; i++)
            {
                // 对角线显式设置为1
                corrMatrix[i, i] = 1.0f;

                for (int j = i + 1; j < featureCount; j++)
                {
                    var col1 = data.Select(row => (double)row[i]).ToArray();
                    var col2 = data.Select(row => (double)row[j]).ToArray();

                    var correlation = Correlation.Pearson(col1, col2);

                    // 处理NaN情况（当某列方差为0时）
                    if (double.IsNaN(correlation))
                    {
                        // 检查两列是否完全相同
                        bool identical = true;
                        for (int k = 0; k < col1.Length; k++)
                        {
                            if (Math.Abs(col1[k] - col2[k]) > 1e-10)
                            {
                                identical = false;
                                break;
                            }
                        }
                        correlation = identical ? 1.0 : 0.0;
                    }

                    corrMatrix[i, j] = corrMatrix[j, i] = (float)correlation;
                }
            }

            return corrMatrix;
        }

        /// <summary>
        /// 计算斯皮尔曼秩相关系数矩阵
        /// 衡量特征之间的单调相关程度，对异常值不敏感
        /// </summary>
        /// <param name="data">特征矩阵，形状为[样本数, 特征数]</param>
        /// <returns>
        /// 秩相关系数矩阵，形状为[特征数, 特征数]
        /// 值域[-1, 1]，值越接近±1表示单调相关性越强
        /// </returns>
        /// <example>
        /// 输入: [[1, 10], [2, 20], [3, 15], [4, 25]]
        /// 输出: 
        ///   [1, 0.8]
        ///   [0.8, 1]  // 特征间存在较强的单调正相关
        /// </example>
        public static float[,] SpearmanCorrelationMatrix(float[][] data)
        {
            if (data == null || data.Length == 0)
                return new float[0, 0];

            if (data.Length < 2)
                throw new ArgumentException("计算相关系数至少需要2个样本");

            int featureCount = data[0].Length;
            var corrMatrix = new float[featureCount, featureCount];

            for (int i = 0; i < featureCount; i++)
            {
                corrMatrix[i, i] = 1.0f;

                for (int j = i + 1; j < featureCount; j++)
                {
                    var col1 = data.Select(row => (double)row[i]).ToArray();
                    var col2 = data.Select(row => (double)row[j]).ToArray();

                    var correlation = Correlation.Spearman(col1, col2);

                    // 处理NaN情况
                    if (double.IsNaN(correlation))
                    {
                        bool identical = true;
                        for (int k = 0; k < col1.Length; k++)
                        {
                            if (Math.Abs(col1[k] - col2[k]) > 1e-10)
                            {
                                identical = false;
                                break;
                            }
                        }
                        correlation = identical ? 1.0 : 0.0;
                    }

                    corrMatrix[i, j] = corrMatrix[j, i] = (float)correlation;
                }
            }

            return corrMatrix;
        }

        
    }
}
